package SmartGrid;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import Tasks.MyRunnable;
import Tasks.ShutDownExecutionEngine;
import Tools.Log;

/**
 * Execute tasks concurrently.
 * TODO:
 * Would like to be able to execute a second task upon completing a first task.
 * @author jeffrey
 *
 */
public class ExecutionEngine {

	public static int tasksRunning = 0;
	public static Map<Runnable, ScheduledFuture<?>> futures;
	public static Object lock = new Object();
	
	public static ScheduledThreadPoolExecutor engine;
	
	public static void init()
	{
		engine = new ScheduledThreadPoolExecutor(20);
		futures = new HashMap<Runnable, ScheduledFuture<?>>();
	}
	
	/**
	 * Exectures a task exactly once
	 * @param r
	 */
	public static void addTask(Runnable r)
	{
		engine.execute(r);
	}
	
	public static void addTask(MyRunnable r)
	{
		addTask((Runnable)r);
	}
	
	/**
	 * Executes a repeating task
	 * @param r task to be executed
	 * @param delay time in milliseconds
	 */
	public static void addRecurringTask(Runnable r, int delay)
	{
		ScheduledFuture<?> future = engine.scheduleWithFixedDelay(r, 0, delay, TimeUnit.MILLISECONDS);
		futures.put(r, future);
		tasksRunning++;
	}
	
	/**
	 * This method is experimental.
	 * Attempts to execute a task and place a lock on the thread that called this method
	 * @param r
	 * @param delay
	 */
	public static void addRecurringTaskAndWait(MyRunnable r, int delay)
	{
		addRecurringTask((Runnable)r, delay);
		r.placeLock();
	}
	
	public static void pauseAllTasks()
	{
		Iterator<Runnable> iter = futures.keySet().iterator();
		while(iter.hasNext())
		{
			Runnable run = iter.next();
			if(run instanceof MyRunnable)
			{
				MyRunnable myrun = (MyRunnable)run;
				myrun.pause();
			}
			else
			{
				Log.Write("Error in ExecutionEngine.pauseAllTasks.  Task is not instance of MyRunnable");
			}
		}
	}
	
	public static void resumeAllTasks()
	{
		Iterator<Runnable> iter = futures.keySet().iterator();
		while(iter.hasNext())
		{
			Runnable run = iter.next();
			if(run instanceof MyRunnable)
			{
				MyRunnable myrun = (MyRunnable)run;
				myrun.resume();
			}
			else
			{
				Log.Write("Error in ExecutionEngine.resumeAllTasks.  Task is not instance of MyRunnable");
			}
		}
	}
	
	/**
	 * Cancels a recurring task
	 * @param r
	 */
	public static void cancelTask(Runnable r)
	{
		if(futures.containsKey(r))
		{
			futures.get(r).cancel(true);
			futures.remove(r);
		}
		tasksRunning--;
	}
	
	/**
	 * Shuts down the execution engine
	 */
	public static void shutDown()
	{
		engine.scheduleWithFixedDelay(new ShutDownExecutionEngine(), 0, 5, TimeUnit.SECONDS);
	}
	
	
}
